package net.chery.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import net.chery.Cons;
import net.chery.entity.VehProduce;
import net.chery.repository.VehProduceRepository;
import net.chery.service.FileEvent;
import net.chery.service.SaveService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * @author gai
 */
@EnableAsync
@Slf4j
@Service
public class SaveServiceImpl implements SaveService {
    private final VehProduceRepository vehProduceRepository;

    private final String tempPath;

    public SaveServiceImpl(VehProduceRepository vehProduceRepository, @Value("${temp-path}") String tempPath) {
        this.vehProduceRepository = vehProduceRepository;
        this.tempPath = tempPath;
    }

    @Override
    public <T>String write2File(Iterable<T> entities) {
        String fileName = UUID.randomUUID() + ".txt";
        File file = FileUtil.newFile(tempPath + File.separator + fileName);
        FileUtil.newFile(tempPath + File.separator + fileName);
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)))) {
            for (T produce : entities) {
                writer.write(JSONUtil.toJsonStr(produce));
                writer.newLine();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return fileName;
    }

    @EventListener
    @Async
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void readFile(FileEvent fileEvent) {
        String path = tempPath + File.separator + fileEvent.getSource();
        log.info("filepath: {}", path);
        File file = FileUtil.newFile(path);
        Date rt=new Date(System.currentTimeMillis()- TimeUnit.HOURS.toMillis(-6));
        log.info("start read");
        Map<String, VehProduce> vehProduceMap = Cons.mapObject(vehProduceRepository
                        .findByCreateTimeGreaterThan(fileEvent.getDate()),
//                        .findAll(),
                VehProduce::getVin);
        List<VehProduce> vehProduces=vehProduceRepository.findUnSyncData(fileEvent.getDate());
        for (VehProduce produce:vehProduces){
            vehProduceMap.put(produce.getVin(),produce);
        }
        Function<String, VehProduce> formCache = vehProduceRepository.getFormCache(vehProduceMap);
        try (BufferedReader read = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
            String json = null;
            while ((json = read.readLine()) != null) {
                if (StringUtils.hasLength(json)) {
                    VehProduce produce = JSONUtil.toBean(json, VehProduce.class);
                    if (StringUtils.hasLength(produce.getLicensePlate()) && produce.getLicensePlate().length() > 8) {
                        log.warn("error licensePlate:{}", produce.getLicensePlate());
                    }
                    if (produce.isNew()) {
                        if(Cons.YES.equals(produce.getSyncStateSh())){
                            produce.setReportTimeSh(rt);
                        }
                        if(Cons.YES.equals(produce.getSaleSyncStateSh())){
                            produce.setSaleReportTimeSh(rt);
                        }
                        setDef(produce,rt);
                        vehProduceMap.put(produce.getVin(), produce);
                    } else {
                        VehProduce cache = formCache.apply(produce.getVin());
                        if(Cons.YES.equals(produce.getSyncStateSh())&&Cons.NO.equals(cache.getSyncStateSh())){
                            produce.setReportTimeSh(rt);
                        }
                        if(Cons.YES.equals(produce.getSaleSyncStateSh())&&Cons.NO.equals(cache.getSaleSyncStateSh())){
                            produce.setSaleReportTimeSh(rt);
                        }
                        BeanUtils.copyProperties(produce, cache);
                        setDef(cache,rt);
                    }
                }
            }
            log.info("finish read");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        vehProduceRepository.saveAll(vehProduceMap.values());
        file.delete();
    }

    private void setDef(VehProduce produce,Date date){
        if(Cons.YES.equals(produce.getSyncState())){
            if(produce.getReportTime()==null){
                produce.setReportTime(date);
            }
        }
        if(Cons.YES.equals(produce.getSaleSyncState())){
            if(produce.getSaleReportTime()==null){
                produce.setSaleReportTime(date);
            }
        }
        if(Cons.YES.equals(produce.getSyncStateSh())){
            if(produce.getReportTimeSh()==null){
                produce.setReportTimeSh(date);
            }
        }
        if(Cons.YES.equals(produce.getSaleSyncStateSh())){
            if(produce.getSaleReportTimeSh()==null){
                produce.setSaleReportTimeSh(date);
            }
        }
    }
}
